home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
SMOOTH11.ARJ
/
SOLVE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-03-30
|
8KB
|
363 lines
/* decomp & solve - solution of linear system
AUTHORS
Forsythe, Malcolm, and Moler, from "Computer Methods for
Mathematical Computations"
translated to C by J. R. Van Zandt
*/
#include <stdio.h>
#include <math.h>
#define aa(i,j) a[ix[i]+j] /* like a[i][j] or a[i*ndim+j] but faster */
double decomp(ndim,n,a,ipvt) /* returns estimate of condition number */
int ndim, /* 2nd declared dimension of a (# columns) */
n; /* rows 0...n-1 and columns 0...n-1 of a are used */
double a[]; /* two dimensional array of matrix coefficients */
int ipvt[]; /* pivot columns */
{ double ek,t,anorm,ynorm,znorm,cond;
int nm1,i,j,k,kp1,kb,km1,m;
static double work[25];
static int ix[25];
if(n>25)
{fprintf(stderr,"decomp: matrix too big\n");
exit(1);
}
/*
double *work;
int *ix;
work=malloc(n*sizeof(double));
ix=malloc(n*sizeof(int));
if(work==0 || ix==0)
{fprintf(stderr,"decomp: no workspace\n");
exit(1);
}
*/
for (i=0; i<n; i++)
ix[i]=i*ndim;
nm1=n-1;
ipvt[nm1]=0;
if(n==1)
{
/*
free(work);
free(ix);
*/
if(a[0]==0.)
return 1.e32;
else
return 1.;
}
/* compute 1-norm of a */
anorm=0.;
for (j=0; j<n; j++)
{t=0.;
for (i=0; i<n; i++)
t += fabs(aa(i,j));
if(t>anorm)
anorm=t;
}
/* Gaussian elimination with partial pivoting */
for (k=0; k<nm1; k++)
{kp1=k+1;
/* Find pivot */
m=k;
for (i=kp1; i<n; i++)
if(fabs(aa(i,k)) > fabs(aa(m,k)))
m=i;
ipvt[k]=m;
t=aa(m,k);
/* printf("pivoting on a[%d][%d] = %8.4f\n",m,k,t); */
if(m!=k)
{ipvt[nm1]=-ipvt[nm1];
aa(m,k)=aa(k,k);
aa(k,k)=t;
}
/* skip step if pivot is zero */
if(t!=0.)
{ /* compute multipliers */
for (i=kp1; i<n; i++)
aa(i,k) = -aa(i,k)/t;
/* interchange and eliminate by columns */
for (j=kp1; j<n; j++)
{t=aa(m,j);
aa(m,j) = aa(k,j);
aa(k,j) = t;
if(t != 0.)
for (i=kp1; i<n; i++)
aa(i,j) += aa(i,k)*t;
}
}
/* showm("After pivoting",a,ndim,n); */
}
/*
cond = (1-norm of a)*(an estimate of 1-norm of
a-inverse) estimate obtained by one step of
inverse iteration for the small singular
vector. This involves solving two systems of
equations, (a-transpose)*y = e and a*z=y there
e is a vector of +1 or -1 chosen to cause
growth in y. Estimate = (1-norm of z)/(1-norm
of y)
*/
/* solve (a-transpose)*y - e */
for (k=0; k<n; k++)
{t=0.;
if(k)
for (i=0; i<k; i++)
t += aa(i,k)*work[i];
if(t<0.) ek = -1.; else ek=1.;
if (aa(k,k) == 0.)
{
/*
free(work);
free(ix);
*/
return 1.e32;
}
work[k] = -(ek+t)/aa(k,k);
}
/* showv("decompose: work1",work,n); */
for (k=n-2; k>=0; k--)
{t=0.;
for (i=k+1; i<n; i++)
t += aa(i,k)*work[k];
work[k] = t;
m=ipvt[k];
if (m!=k)
{t=work[m];
work[m] = work[k];
work[k]=t;
}
}
ynorm=0.;
for (i=0; i<n; i++)
ynorm += fabs(work[i]);
/* solve a*z=y */
solve(ndim, n, a, work, ipvt);
znorm=0.;
for (i=0; i<n; i++)
znorm += fabs(work[i]);
/* estimate condition */
cond=anorm*znorm/ynorm;
if(cond<1.)
cond=1.;
/*
free(work);
free(ix);
*/
return cond;
}
double invert(ndim,n,a,x) /* returns estimate of condition number of matrix */
int ndim, /* 2nd declared dimension of a and x (# columns) */
n; /* rows 0...n-1 and columns 0...n-1 of a are used */
double a[], /* matrix to be inverted */
x[]; /* resulting inverse */
{ int i, j;
double cond, condp1;
static double work[25];
static int ipvt[25];
if(n>25)
{fprintf(stderr,"invert: matrix too big\n");
exit(1);
}
/*
double *work;
int *ipvt;
ipvt=malloc(n*sizeof(int));
work=malloc(n*sizeof(double));
if(ipvt==0 || work==0)
{fprintf(stderr,"invert: not enough memory\n");
exit(1);
}
*/
cond=decomp(ndim,n,a,ipvt);
/* printf("invert: cond = %f\n\n",cond);
printf("invert: ipvt\n");
for (i=0; i<n; i++)
printf("%8d \n",ipvt[i]);
*/
condp1=cond+1.;
if(condp1==cond)
{
/*
free(work);
free(ipvt);
*/
return cond;
}
for (i=0; i<n; i++)
{for (j=0; j<n; j++)
work[j]=0.;
work[i]=1.;
/* showv("invert: RHS",work,n); */
solve(ndim,n,a,work,ipvt);
for (j=0; j<n; j++)
x[j*ndim+i]=work[j];
}
/*
free(work);
free(ipvt);
*/
return cond;
}
solve (ndim,n,a,b,ipvt)
int ndim, /* 2nd declared dimension of a (# columns) */
n; /* order of matrix a: rows 0...n-1 & columns 0...n-1 are used */
double a[], /* triangularized matrix obtained from decomp */
b[]; /* right hand side vector */
int ipvt[]; /* pivot vector obtained from decomp */
{ int kb,km1,nm1,kp1,i,k,m;
double t;
static int ix[25];
if(n>25)
{fprintf(stderr,"solve: matrix too big\n");
exit(1);
}
/*
int *ix;
ix=malloc(n*sizeof(int));
if(ix==0)
{fprintf(stderr,"solve: no workspace\n");
exit(1);
}
*/
for (i=0; i<n; i++)
ix[i]=i*ndim;
/* showm("solve: decomposed matrix",a,ndim,n);
showv("solve: RHS",b,n); */
/* forward elimination */
if(n!=1)
{nm1=n-1;
for (k=0; k<nm1; k++)
{kp1=k+1;
m=ipvt[k];
t=b[m];
b[m]=b[k];
b[k]=t;
for (i=kp1; i<n; i++)
b[i] += aa(i,k)*t;
}
/* showv("\nafter forward elimination",b,n); */
/* back substitution */
for (k=nm1; k; k--)
{b[k] /= aa(k,k);
t=-b[k];
for (i=0; i<k; i++)
b[i] += aa(i,k)*t;
}
}
b[0] /= a[0];
/* showv("\nafter back substitution",b,n); */
/*
free(ix);
*/
}
#ifdef TEST
/* sample program for decomp and solve */
main()
{ double x[13][13], p[13][13], a[13][13], b[13], cond, condp1;
int ipvt[13], i, j, k, n, ndim;
ndim=13;
n=3;
a[0][0]=10.;
a[1][0]=-3.;
a[2][0]= 5.;
a[0][1]=-7.;
a[1][1]= 2.;
a[2][1]=-1.;
a[0][2]= 0.;
a[1][2]= 6.;
a[2][2]= 5.;
for (i=0; i<n; i++)
{for (j=0; j<n; j++)
printf("%8.4f ",a[i][j]);
printf("\n");
}
printf("\n");
cond=decomp(ndim,n,a,ipvt);
printf("cond = %f\n\n",cond);
printf("\nipvt\n");
for (i=0; i<n; i++)
printf("%8d \n",ipvt[i]);
condp1=cond+1.;
if(condp1==cond) exit();
b[0]=7.;
b[1]=4.;
b[2]=6.;
showv("RHS",b,n);
solve(ndim,n,a,b,ipvt);
showv("solution",b,n);
a[0][0]=10.;
a[1][0]=-3.;
a[2][0]= 5.;
a[0][1]=-7.;
a[1][1]= 2.;
a[2][1]=-1.;
a[0][2]= 0.;
a[1][2]= 6.;
a[2][2]= 5.;
showm("a, matrix to be inverted",a,ndim,n);
cond=invert(ndim,n,a,x);
printf("cond = %f\n\n",cond);
printf("ipvt\n");
for (i=0; i<n; i++)
printf("%8d \n",ipvt[i]);
condp1=cond+1.;
if(condp1==cond) exit();
showm("x, inverse",x,ndim,n);
a[0][0]=10.;
a[1][0]=-3.;
a[2][0]= 5.;
a[0][1]=-7.;
a[1][1]= 2.;
a[2][1]=-1.;
a[0][2]= 0.;
a[1][2]= 6.;
a[2][2]= 5.;
for (k=0; k<n; k++)
for (j=0; j<n; j++)
{p[k][j]=0.;
for (i=0; i<n; i++)
p[k][j] += a[k][i]*x[i][j];
}
showm("a*x",p,ndim,n);
for (k=0; k<n; k++)
for (j=0; j<n; j++)
{p[k][j]=0.;
for (i=0; i<n; i++)
p[k][j] += x[k][i]*a[i][j];
}
showm("x*a",p,ndim,n);
}
showv(s,a,n) char *s; double a[]; int n;
{ int i,j;
printf("%s\n",s);
for (i=0; i<n; i++)
printf("%8.4f \n",a[i]);
printf("\n");
}
showm(s,a,ndim,n) char *s; double a[]; int ndim,n;
{ int i,j;
printf("%s\n",s);
for (i=0; i<n; i++)
{for (j=0; j<n; j++)
printf("%8.4f ",a[i*ndim+j]);
printf("\n");
}
printf("\n");
}
#endif